#include "RoomBase.h"
#include "PlayerBase.h"
#include "Hall.h"
#include "StackTrace.h"
#include "HallConfig.h"
#include "msg_errno.h"
#include "msg_common.h"
#include "msg_group.h"
#include "msg_roomcenter.h"
#include "msg_msgid.h"
#include "SessionBase.h"

using namespace SGLib;
using namespace std;

CRoomBase::CRoomBase(s32 id) : 
	m_id(id),
	m_players(NULL),
	m_curPlayerCount(0),
	m_state(E_RoomState_Idle)
{
	s32 count = CHall::Instance().MaxRoomPlayerCount();
	m_players = new CPlayerBase*[ count ];
	for( s32 i=0; i<count; ++i )
	{
		m_players[i] = NULL;
	}
    m_ante = 0;
    m_passwd = "";
    m_name = "";
    
    m_friendData._creater = 0;
    m_friendData._maxRound = 0;
    m_friendData._curRound = 0;
    m_friendData._number = 0;
    m_friendData._cfg = "";
    m_friendData._dismissState = -1;
    m_friendData._waitDismissUser.clear();
}

CRoomBase::~CRoomBase()
{
	SAFE_DELETE_ARRAY( m_players );
}

void CRoomBase::Clean()
{
	m_curPlayerCount = 0;
	m_state = E_RoomState_Idle;
    m_ante = CHallConfig::Instance().GetCfg().ante;
    m_passwd = "";
    m_name = "";
    m_beholder.clear();
    m_friendData._creater = 0;
    m_friendData._maxRound = 0;
    m_friendData._curRound = 0;
    m_friendData._number = 0;
    m_friendData._cfg = "";
    m_friendData._dismissState = -1;
    m_friendData._waitDismissUser.clear();
    m_prioritySeatno = -1;
}

void CRoomBase::OnFriendGameDismiss(s32 endstate)
{
   
    std::string groupLog("[");
    bool bf = true;
    s32 count = CHall::Instance().MaxRoomPlayerCount();
    for( s32 i=0; i<count; ++i )
    {
        if( m_players[i] )
        {
            CHall::Instance().LogFriendGameRoundData( *m_players[i], endstate );
            char buf[64] = {0};
            snprintf(buf, sizeof(buf), bf ? "[%llu,%lld]" : ",[%llu,%lld]", m_players[i]->UserId(), m_players[i]->GetAllScore());
            bf = false;
            groupLog += buf;
        }
    }
    if (0 == m_friendData._groupid || m_friendData._curRound < 1) return;
    groupLog += "]}";
    group::OnlineGroupChatReq chatReq;
    chatReq.gid = m_friendData._groupid;
    chatReq.msg.senderid = 0;
    chatReq.msg.ttype = commonproto::TARGET_TYPE_GROUP;
    chatReq.msg.tid = m_friendData._groupid;
    chatReq.msg.chattype = commonproto::E_ChatType_Text;
    char buf[64] = {0};
    snprintf(buf, sizeof(buf), "{\"n\":%d,\"t\":%llu,\"d\":", m_friendData._number, TIME_NOW);
    chatReq.msg.chatcontent += buf; 
    chatReq.msg.chatcontent += groupLog;
    CHall::Instance().SendMsg2Center(msgid::SERVER_CENTER_GROUP_MSG, chatReq);
    LOG_DEBUG( "[%s][%s][%d] gid[%llu] content[%s] ", 
        __FILE__, __FUNCTION__, __LINE__, chatReq.gid, chatReq.msg.chatcontent.c_str());  
}

s32 CRoomBase::Id()
{
	return m_id;
}

CRoomBase::ERoomState CRoomBase::State()
{
	return m_state;
}

void CRoomBase::SetState(CRoomBase::ERoomState state)
{
	m_state = state;
}

s32 CRoomBase::CurPlayerCount()
{
	return m_curPlayerCount;
}

s32 CRoomBase::CurBeholderCount()
{
	return (s32)m_beholder.size();
}

CPlayerBase* CRoomBase::GetPlayerInSeat(s32 seatno)
{
	if( seatno < 0 || seatno > CHall::Instance().MaxRoomPlayerCount() )
	{
		return NULL;
	}
	return m_players[seatno];
}

CPlayerBase* CRoomBase::FindPlayer(u64 userid)
{
	map<u64, CPlayerBase*>::iterator it = m_beholder.find( userid );
    if( it != m_beholder.end() )
    {
        return it->second;
    }

    s32 count = CHall::Instance().MaxRoomPlayerCount();
	for( s32 i=0; i<count; ++i )
	{
		if( m_players[i] && m_players[i]->UserId() == userid )
		{
            return m_players[i];
		}
	}

    return NULL;
}

bool CRoomBase::IsAllPlayerReady()
{
    s32 count = CHall::Instance().MaxRoomPlayerCount();
	for( s32 i=0; i<count; ++i )
	{
		if( m_players[i] && m_players[i]->State() != CPlayerBase::E_PlayerState_Ready )
		{
			return false;
		}
	}
	return (m_curPlayerCount > 0);
}

s32 CRoomBase::GetPlayerReadyCount()
{
    s32 rcount = 0;
    s32 count = CHall::Instance().MaxRoomPlayerCount();
	for( s32 i=0; i<count; ++i )
	{
		if( m_players[i] && m_players[i]->State() == CPlayerBase::E_PlayerState_Ready )
		{
			++rcount;
		}
	}
	return rcount;
}

void CRoomBase::TryGetPriorityPlayer(CPlayerBase &player, bool bleave)
{
    if (!CHall::Instance().IsFriendMode()) {
        return; 
    }

    bool bneedNotice = false;
    if (!bleave) { // ready
        if (1 == GetPlayerReadyCount() && player.UserId() != m_friendData._creater && !CreaterInRoom()) {
            m_prioritySeatno = player.GetSeatNo();  
            bneedNotice = true;
        } 
    } else {
        if (m_prioritySeatno == player.GetSeatNo() || player.UserId() == m_friendData._creater) {
            // select next as the priority one 
            bneedNotice = true;
            s32 fromSeat = player.GetSeatNo();
            s32 count = CHall::Instance().MaxRoomPlayerCount();
            s32 i = (fromSeat+1) % count;
	        for( ; i != fromSeat; )
	        {
	        	if( m_players[i] && m_players[i]->State() == CPlayerBase::E_PlayerState_Ready )
	        	{
	        		m_prioritySeatno = i;
                    break;
	        	}
                i = (i+1)%count;
	        }
        } 
    }

    if (bneedNotice && m_prioritySeatno >= 0) {
        commonproto::SCFriendRoomPrioritySeatnoNtf ntf;
        ntf.seat = m_prioritySeatno;
        BroadcastMsg( commonproto::SC_FRIEND_ROOM_PRIORITY_SEATNO, ntf );
    }
}

s32 CRoomBase::GetAnte()
{
    return m_ante;
}

void CRoomBase::SetAnte(s32 ante)
{
    m_ante = ante;
}

s32 CRoomBase::FindFreeSeat()
{
    s32 count = CHall::Instance().MaxRoomPlayerCount();
    for( s32 i=0; i<count; ++i )
    {
        if( !m_players[i] )
        {
            return i;
        }
    }
    return INVALID_SEAT; 
}

void CRoomBase::ForceAllPlayerReady()
{
    s32 count = CHall::Instance().MaxRoomPlayerCount();
    for( s32 i=0; i<count; ++i )
    {
        if( m_players[i] && m_players[i]->State() == CPlayerBase::E_PlayerState_WaitInRoom )
        {
            PlayerReady( *m_players[i] );
        }
    }
}

void CRoomBase::DismissFriendRoom(CPlayerBase &player)
{
    if( GetFriendData()._curRound == 0 )
    {
        if( CanDismissFriendRoom(player) == errorcode::E_ErrorCode_Success )
        {
            // 发起解散时设置玩家解散状态标记
            player.SetDismissState( commonproto::E_FRoomEnd_Originator );
            s32 count = CHall::Instance().MaxRoomPlayerCount();
            for( s32 i=0; i<count; ++i )
            {
                if( m_players[i] && m_players[i]->UserId() != player.UserId() )
                {
                    m_players[i]->SetDismissState( commonproto::E_FRoomEnd_Dismiss );
                }
            }

            LOG_INFO( "[%s] player[%llu] dismiss room. creater[%llu]", 
                __FUNCTION__, player.UserId(), GetFriendData()._creater );
            OnFriendGameDismiss( commonproto::E_FRoomEnd_Dismiss );
            vector<CPlayerBase*> _breakers;
            _DumpAllBreakPlayers( _breakers, true );
            Dissolve( commonproto::E_DissolveReason_Destory );
            CHall::Instance().NotifyRoomCenterGameStop( *this, roomcenter::GameStopReason_Dismiss );
            _CleanBreakPlayers( _breakers );
        }
        else
        {
            LOG_ERROR( "[%s] user[%llu] cannot dissmiss. creater[%llu]", 
                __FUNCTION__, player.UserId(), GetFriendData()._creater );
        }
    }
    else
    {
        LOG_INFO( "[%s] user[%llu] dismiss room. indismiss[%d]", 
            __FUNCTION__, player.UserId(), GetFriendData()._dismissState?1:0 );
        if( GetFriendData()._dismissState >= 0 )
        {
            return;
        }
        // 发起解散时设置玩家解散状态标记
        player.SetDismissState( commonproto::E_FRoomEnd_Originator );
        GetFriendData()._dismissState = 0;
        commonproto::SCFriendRoomAskAgreeDismiss m;
        m.uid = player.UserId();
        BroadcastMsg( commonproto::SC_FRIEND_ROOM_ASK_AGREE_DISMISS, m, player.UserId(), false );

        s32 count = CHall::Instance().MaxRoomPlayerCount();
        u64 expire = TIME_NOW + 20;
        GetFriendData()._dismissEndTime = expire;
        for( s32 i=0; i<count; ++i )
        {
            if( m_players[i] && m_players[i]->UserId() != player.UserId() )
            {
                m_players[i]->SetDismissState( commonproto::E_FRoomEnd_Agree );
                GetFriendData()._waitDismissUser.insert( m_players[i]->GetSeatNo() );
                m_players[i]->AddMoreAction( commonproto::Action_AgreeDismissFriendRoom, expire );
            }
        }
    }
}

void CRoomBase::LeaveFriendRoom(CPlayerBase &player)
{
    if( GetFriendData()._curRound > 0 /* || 
        GetFriendData()._creater == player.UserId() */)
    {
        LOG_ERROR( "[%s] player[%llu] cannot leave. curRound[%d] creater[%llu]", __FUNCTION__,
            player.UserId(), GetFriendData()._curRound, GetFriendData()._creater );
        return;
    }
    LOG_DEBUG( "[%s] player[%llu]", __FUNCTION__, player.UserId() );
    CHall::Instance().PlayerLeaveHall( player, commonproto::E_LeaveReason_Force );
}

void CRoomBase::AgreeDismissFriendRoom(CPlayerBase &player, s32 agree, bool timeout)
{
    s32 disstate = commonproto::E_FRoomEnd_Dismiss;
    if( timeout )
    {
        disstate = (agree == 1) ? commonproto::E_FRoomEnd_TimeOut_Agree : commonproto::E_FRoomEnd_TimeOut_Disagree;
    }
    else
    {
        disstate = (agree == 1) ? commonproto::E_FRoomEnd_Agree : commonproto::E_FRoomEnd_Disagree;
    }
    player.SetDismissState( disstate );

    LOG_INFO( "[%s] player[%llu] agree[%d] dismissState[%d] waitdismissCount[%d] disstate[%d]", __FUNCTION__,
        player.UserId(), agree, GetFriendData()._dismissState,
        (s32)GetFriendData()._waitDismissUser.size(), disstate );

    if( GetFriendData()._dismissState == -1 )
    {
        return;
    }

    commonproto::SCFriendRoomAgreeDismissNtf m;
    m.uid = player.UserId();
    m.agree = (s8)agree;
    BroadcastMsg( commonproto::SC_FRIEND_ROOM_AGREE_DISMISS_NTF, m );

    ++GetFriendData()._dismissState;
    if( agree == 0 )
    {
        // not agree, clean dismiss state
        _ClearAllAgreeDismissAction();
    }
    else
    {
        if( GetFriendData()._dismissState == (s32)GetFriendData()._waitDismissUser.size() )
        { 
            // can dismiss game room
            _ClearAllAgreeDismissAction();
            OnFriendGameDismiss( commonproto::E_FRoomEnd_Dismiss );
            vector<CPlayerBase*> _breakers;
            _DumpAllBreakPlayers( _breakers, true);
            Dissolve( commonproto::E_DissolveReason_Destory );
            CHall::Instance().NotifyRoomCenterGameStop( *this, roomcenter::GameStopReason_Dismiss );
            _CleanBreakPlayers( _breakers );
        }
        else
        {
            player.DelMoreAction( commonproto::Action_AgreeDismissFriendRoom );
        }
    }
}

void CRoomBase::StartGameFriendRoom(CPlayerBase &player)
{
    if( CanStartFriendRoomGame(player) != errorcode::E_ErrorCode_Success )
    {
        return;
    }

    s32 minReadyCount = CHall::Instance().MinRoomPlayerCount();
    LOG_DEBUG( "[%s] player[%llu] startgame. [%d/%d] curRound[%d]", __FUNCTION__,
        player.UserId(), CurPlayerCount(), minReadyCount, GetFriendData()._curRound );
    if( CurPlayerCount() < minReadyCount || GetFriendData()._curRound > 0 )
    {
        return;
    }

    ForceAllPlayerReady();
}

void CRoomBase::NotifyFriendRoomInfo(CPlayerBase &player)
{
    if( !CHall::Instance().IsFriendMode() )
    {
        return;
    }
    commonproto::SCFriendRoomInfoNtf _ntf;
    _ntf.creater = GetFriendData()._creater;
    _ntf.round = GetFriendData()._maxRound;
    _ntf.number = GetFriendData()._number;
    _ntf.gamecfg = GetFriendData()._cfg;
    _ntf.curround = GetFriendData()._curRound;
    player.SendMsg( commonproto::SC_FRIEND_ROOM_INFO_NTF, _ntf );
}

void CRoomBase::NotifyFriendRoomDismissProgress(CPlayerBase &player)
{
    if( !CHall::Instance().IsFriendMode() )
    {
        return;
    }
    if( GetFriendData()._dismissState == -1 )
    {
        return;
    }
    commonproto::SCFriendRoomDismissProgress msg;
    s32 count = CHall::Instance().MaxRoomPlayerCount();
    msg.timeLeft = GetFriendData()._dismissEndTime - TIME_NOW;
    for( s32 i=0; i<count; ++i )
    {
        if( m_players[i] )
        {
            if( m_players[i]->GetDismissState() == commonproto::E_FRoomEnd_Originator )
            {
                msg.seat = i;
            }
            else
            {
                if( !m_players[i]->HasMoreAction(commonproto::Action_AgreeDismissFriendRoom) )
                {
                    msg.agreeseat.push_back( i );
                }
            }
        }
    }
    player.SendMsg( commonproto::SC_FRIEND_ROOM_DISMISS_PROGRESS, msg );
}

s32 CRoomBase::GamingPlayerCount()
{
    s32 n = 0;
    s32 count = CHall::Instance().MaxRoomPlayerCount();
    for( s32 i=0; i<count; ++i )
    {
        if( m_players[i] && m_players[i]->State() == CPlayerBase::E_PlayerState_Gaming )
        {
            ++n;
        }
    }
    return n;

    return 0;
}

s32 CRoomBase::RobotPlayerCount()
{
    s32 n = 0;
    s32 count = CHall::Instance().MaxRoomPlayerCount();
    for( s32 i=0; i<count; ++i )
    {
        if( m_players[i] && m_players[i]->IsRobot() )
        {
            ++n;
        }
    }
    return n;
}

s32 CRoomBase::CanEnter(CPlayerBase &player, int seatno, const std::string &passwd)
{
    if( m_passwd != "" && m_passwd != passwd )
    {
        return errorcode::E_ErrorCode_RoomPwdError;
    }

	s32 limit = 0;
	s32 cur = 0;
	if( seatno == INVALID_SEAT )
	{
		cur = (s32)m_beholder.size();
		limit = CHall::Instance().MaxRoomBeholderCount();
	}
	else
	{
		cur = m_curPlayerCount; 
		limit = CHall::Instance().MaxRoomPlayerCount();
	}

	if( cur == limit )
	{
		// 房间人满了
		return errorcode::E_ErrorCode_RoomIsFull;
	}

	if( PlayerInRoom(player) )
	{
		// 已在房间中
		return errorcode::E_ErrorCode_AleardyInRoom;
	}

	if( seatno >= 0 )
	{
		SELF_ASSERT( seatno < limit, return false; );
		if( m_players[seatno] != NULL )
		{
			// 此位置有人
			return errorcode::E_ErrorCode_SeatNotEmpty;
		}
	}
    
    if( CHallConfig::Instance().GetCfg().roomMode == E_RoomMode_Friend &&
        State() == CRoomBase::E_RoomState_Idle )
    {
        return errorcode::E_ErrorCode_NotOpen;
    }

    if( CHallConfig::Instance().GetCfg().roomMode == E_RoomMode_Friend &&
        (State() == CRoomBase::E_RoomState_Gaming || m_friendData._curRound > 0))
    {
        return errorcode::E_ErrorCode_InGaming;
    }


	return errorcode::E_ErrorCode_Success;
}

s32 CRoomBase::CanLeave(CPlayerBase &player, s32 reason)
{
	if( !PlayerInRoom(player) )
    {
        return errorcode::E_ErrorCode_NotInRoom;
    }
	
    if( CHallConfig::Instance().GetCfg().roomMode == E_RoomMode_Friend &&
        reason != commonproto::E_LeaveReason_Force )
    {
        return errorcode::E_ErrorCode_InGaming;
    }

    return errorcode::E_ErrorCode_Success;
}

s32 CRoomBase::CanSitDown(CPlayerBase &player, int seatno)
{
    if( seatno < 0 || seatno >= CHall::Instance().MaxRoomPlayerCount() )
    {
        return errorcode::E_ErrorCode_Unknown;
    }

    if( !PlayerInRoom(player) )
    {
        return errorcode::E_ErrorCode_NotInRoom;
    }

    if( PlayerInSeat(player) )
    {
        return errorcode::E_ErrorCode_AleardyInSeat;
    }

    if( m_players[seatno] )
    {
        return errorcode::E_ErrorCode_SeatNotEmpty;
    }
	
    return errorcode::E_ErrorCode_Success;
}

s32 CRoomBase::CanStandUp(CPlayerBase &player)
{
    if( !PlayerInRoom(player) )
    {
        return errorcode::E_ErrorCode_NotInRoom;
    }
	
    if( !PlayerInSeat(player) )
    {
        return errorcode::E_ErrorCode_NotInSeat;
    }

    return errorcode::E_ErrorCode_Success;
}

s32 CRoomBase::CanReady(CPlayerBase &player)
{
    if( !PlayerInRoom(player) )
    {
        return errorcode::E_ErrorCode_NotInRoom;
    }
	
    if( !PlayerInSeat(player) )
    {
        return errorcode::E_ErrorCode_NotInSeat;
    }

    return errorcode::E_ErrorCode_Success;
}


bool CRoomBase::CanChat(CPlayerBase &player, s8 chattype, const std::string &chatcontent, s8 anonymous, std::vector<u64> &receiver)
{
    return true;
}

bool CRoomBase::CanSetRoomAnte(CPlayerBase &player, int ante)
{
    return true;
}

s32 CRoomBase::CanKickOut(CPlayerBase &player, u64 kickuser)
{
    CPlayerBase *kuser = FindPlayer( kickuser );
    if( !kuser )
    {
        return errorcode::E_ErrorCode_NotInRoom;
    }

    // 默认必须是好友局并且player是房主,并且游戏尚未开局
    if( !CHall::Instance().IsFriendMode() ||
        (m_friendData._creater != player.UserId() && m_prioritySeatno != player.GetSeatNo()) ||
        m_friendData._curRound > 0 )
    {
        return errorcode::E_ErrorCode_NoRight;
    }

    return errorcode::E_ErrorCode_Success;
}

s32 CRoomBase::CanUseInteractItem(CPlayerBase &player, s32 to, s32 item)
{
    if (to >= CHall::Instance().MaxRoomPlayerCount() || NULL == m_players[to]) {
        return errorcode::E_ErrorCode_NotInRoom;
    }
    if (to == player.GetSeatNo()) {
        return errorcode::E_ErrorCode_UseItemToSelf;     
    }
    u64 now = TIME_NOW;
    if (now - player.m_useItemLastTime < (u64)CHallConfig::Instance().GetCfg().useInteractItemInterval ) {
        return  errorcode::E_ErrorCode_UseItemFreqt;
    }
    publicproto::ItemInfo *useritem = player.GetItem( publicproto::ITEM_ID_ROOMCARD );
    int price = CHallConfig::Instance().GetCfg().interactItemPrice;
    if( useritem == NULL || useritem->data < (u64)price )
    {
        return errorcode::E_ErrorCode_NotEnoughMoney;
    }
    if( price > 0 )
    {
        player.UpdateItemData(
            publicproto::ITEM_ID_ROOMCARD, publicproto::ITEMCLASS_TYPE_NUMBER, -price, 1021, item );
    }
    player.m_useItemLastTime = now;
    //检测金钱，检测item 
    return errorcode::E_ErrorCode_Success;
}

s32 CRoomBase::CanStartFriendRoomGame(CPlayerBase &player)
{
    if( GetFriendData()._creater != player.UserId() )
    {
        LOG_ERROR( "[%s] player[%llu] cannot start. creater[%llu]", __FUNCTION__,
            player.UserId(), GetFriendData()._creater );
        return errorcode::E_ErrorCode_NoRight;
    }
    return errorcode::E_ErrorCode_Success;
}

s32 CRoomBase::CanDismissFriendRoom(CPlayerBase &player)
{
    if( GetFriendData()._creater != player.UserId() )
    {
        LOG_ERROR( "[%s] player[%llu] cannot dismiss. creater[%llu]", __FUNCTION__,
            player.UserId(), GetFriendData()._creater );
        return errorcode::E_ErrorCode_NoRight;
    }
    return errorcode::E_ErrorCode_Success;
}

bool CRoomBase::CheckGameStart(bool needAllReady, bool decroomcard)
{
    s32 minReadyCount = CHall::Instance().MinRoomPlayerCount();
    if( m_curPlayerCount < minReadyCount )
    {
        return false;
    }

    vector<s32> readyPos;
    s32 count = CHall::Instance().MaxRoomPlayerCount();
    for( s32 i=0; i<count; ++i )
    {
        if( m_players[i] )
        {
            if( m_players[i]->State() == CPlayerBase::E_PlayerState_Ready )
            {
                readyPos.push_back( i );
            }
        }
    }

    if( (s32)readyPos.size() < minReadyCount )
    {
        return false;
    }
    
    if( needAllReady && (s32)readyPos.size() < CurPlayerCount() )
    {
        return false;
    }

    vector<u64> uids;
    vector<s32>::iterator it = readyPos.begin();
    for( ; it != readyPos.end(); ++it )
    {
        SELF_ASSERT( m_players[*it], return false; )
            m_players[*it]->SetState( CPlayerBase::E_PlayerState_Gaming );
        uids.push_back( m_players[*it]->UserId() );
    }
    SetState( CRoomBase::E_RoomState_Gaming );
    CHall::Instance().NotifyRoomCenterGameStart( *this, uids, decroomcard );
	m_gameStarttime = TIME_NOW;
    return true;
}

void CRoomBase::GameEnd(bool needCleanBreakUsers)
{
    // 先检查游戏内活动
    _GameEndCheckActivity();

    vector<CPlayerBase*> logBreakPlayers;
    vector<CPlayerBase*> cleanPlayers;
    SetState( CRoomBase::E_RoomState_Waiting );
    s32 count = CHall::Instance().MaxRoomPlayerCount();
    for( s32 i=0; i<count; ++i )
    {
        if( m_players[i] )
        {
            m_players[i]->SetState( CPlayerBase::E_PlayerState_WaitInRoom );
            if( needCleanBreakUsers && m_players[i]->IsOffline() )
            {
                cleanPlayers.push_back( m_players[i] );
                logBreakPlayers.push_back( m_players[i] );
            }
            if (m_players[i]->HasGame()) {
                m_players[i]->IncGameTimes(1);
                m_players[i]->GetBasicInfo().exp += m_players[i]->GetExp( m_players[i]->GetCurScore() );
            }
        }
    }

    bool cleanflag = true;
    if( CHallConfig::Instance().GetCfg().roomMode == E_RoomMode_Friend )
    {
        if( CheckFriendGameRoundEnd() )
        {
            cleanPlayers.clear();
            s32 count = CHall::Instance().MaxRoomPlayerCount();
            for( s32 i=0; i<count; ++i )
            {
                if( m_players[i] )
                {
                    cleanPlayers.push_back( m_players[i] );
                }
            }

            OnFriendGameDismiss( commonproto::E_FRoomEnd_Normal );
            Dissolve( commonproto::E_DissolveReason_Normal);
            CHall::Instance().NotifyRoomCenterGameStop( *this, roomcenter::GameStopReason_Normal );
        }
        else
        {
            cleanflag = false;
        }
        LOG_INFO( "[%s][%s][%d] room[%d] GameEnd. round[%d/%d] cleanflag[%d]",
            __FILE__, __FUNCTION__, __LINE__, Id(), 
            GetFriendData()._curRound, GetFriendData()._maxRound, cleanflag?1:0 );
    }

    int n = 0;
    if( cleanflag )
    {
        vector<CPlayerBase*>::iterator it = cleanPlayers.begin();
        for( ; it != cleanPlayers.end(); ++it )
        {
            if( *it )
            {
                ++n;
                CHall::Instance().PlayerLeaveHall( *(*it), commonproto::E_LeaveReason_Kick );
                LOG_DEBUG( "[%s][%s][%d] room[%d] GameEnd. clean user[%llu] addistatus[%u]",
                        __FILE__, __FUNCTION__, __LINE__, Id(), (*it)->UserId(), (*it)->AddiStatus() );
            }
        }
        _logBreakPlayersGameEnd( logBreakPlayers );
    }
    LOG_INFO( "[%s][%s][%d] room[%d] GameEnd. clean [%d] break player. allBreakPlayer[%d] logbreak[%d]",
        __FILE__, __FUNCTION__, __LINE__, 
        Id(), n, (s32)cleanPlayers.size(), (s32)logBreakPlayers.size() );
	//过夜局，更新 
	if (!IsSameDay(m_gameStarttime, TIME_NOW)) {
		CHall::Instance().UpdateGameTimes2DBProxy(this, NULL, 1);	
	}
	m_gameStarttime = 0;
}

void CRoomBase::PlayerEnter(CPlayerBase &player, int seatno, const std::string &passwd)
{
	s32 ret = CanEnter( player, seatno, passwd );
	SELF_ASSERT( ret == errorcode::E_ErrorCode_Success, return; );

    {
		commonproto::SCUserEnterRoomNtf ntf;
		ntf.userinfo.userid = player.UserId();
		ntf.userinfo.seatno = seatno;
		ntf.userinfo.isready = 0;
        ntf.userinfo.basicinfo = player.GetBasicInfo();
        ntf.userinfo.gamedata = player.GetGameData();
		BroadcastMsg( commonproto::SC_USER_ENTER_ROOM_NTF, ntf );

        NotifyRoomBasicInfos( player );
	}

	if( seatno >= 0 )
	{
		m_players[ seatno ] = &player;
		++m_curPlayerCount;

        if( m_curPlayerCount >= CHall::Instance().MaxRoomPlayerCount() )
        {
            // 人满了从halffull队列中移除
            CRoomManager::Instance().RemoveHalfFullRoom( Id() );
        }
	}
	else
	{
		m_beholder[ player.UserId() ] = &player;
	}
	player.EnterRoom( *this, seatno );
    NotifyUserLocationInfo();
   
    s32 rmode = CHallConfig::Instance().GetCfg().roomMode; 
    if( rmode == E_RoomMode_Friend )
    {
        NotifyFriendRoomInfo( player );
    }
    else if( rmode == E_RoomMode_Manual )
    {
        CHall::Instance().BroadcastUserEnterRoom( player, Id(), seatno );
    }
    else if( rmode == E_RoomMode_Match )
    {
        CHall::Instance().PlayerReady( player );
	}

    OnPlayerEnter( player );
    if( CurPlayerCount() + CurBeholderCount() == 1 )
    {
        OnFirstPlayerEnter( player );
        SetState( CRoomBase::E_RoomState_Waiting );
    }
    if (player.UserId() == m_friendData._creater) {
        m_prioritySeatno = -1; 
    }
    LOG_INFO( "PlayerEnter player[%llu,%llu,%llu] enter room[%d] mode[%d] countInRoom[%d] seatno[%d] beholderCount[%d]", 
            player.GateId(), player.ClientId(), player.UserId(), Id(), CHallConfig::Instance().GetCfg().roomMode,
            m_curPlayerCount, seatno, m_beholder.size() );
}

void CRoomBase::PlayerLeave(CPlayerBase &player, s32 reason)
{
    s32 ret = CanLeave( player, reason );
	SELF_ASSERT( ret == errorcode::E_ErrorCode_Success, return; );
	OnBeforePlayerLeave( player );

    s32 seatno = player.GetSeatNo();
    if( seatno != INVALID_SEAT )
    {
        m_players[seatno] = NULL;
        --m_curPlayerCount;
        
        // 有人离开房间重新加入到halffull队列
        CRoomManager::Instance().AddHalfFullRoom( Id() );
    }
    else
    {
		map<u64, CPlayerBase*>::iterator it = m_beholder.find( player.UserId() );
        SELF_ASSERT( it != m_beholder.end(), return; );
        m_beholder.erase( it );
    }
    TryGetPriorityPlayer(player, true);
    player.LeaveRoom();
    
    commonproto::SCUserLeaveRoomNtf ntf;
    ntf.userid = player.UserId();
	BroadcastMsg( commonproto::SC_USER_LEAVE_ROOM_NTF, ntf );

    s32 rmode = CHallConfig::Instance().GetCfg().roomMode; 
    if( rmode == E_RoomMode_Manual )
    {
        CHall::Instance().BroadcastUserLeaveRoom( player, Id(), seatno );
    }

    OnPlayerLeave( player, seatno );
	if( CurPlayerCount() + CurBeholderCount() == 0 )
	{
        OnLastPlayerLeave( player );
        if( rmode != E_RoomMode_Friend )
        {
            // 非好友房需要重置状态.好友房一直存在
		    SetState( CRoomBase::E_RoomState_Idle );
            Clean();
            CRoomManager::Instance().PutRoom( Id() );
        }
	}

    LOG_INFO( "PlayerLeave player[%llu,%llu,%llu] leave room[%d] countInRoom[%d] seatno[%d] beholderCount[%d] reason[%d]", 
		player.GateId(), player.ClientId(), player.UserId(), Id(), 
        m_curPlayerCount, player.GetSeatNo(), m_beholder.size(), reason );
}

void CRoomBase::PlayerSitDown(CPlayerBase &player, int seatno)
{
    s32 ret = CanSitDown( player, seatno );
	SELF_ASSERT( ret == errorcode::E_ErrorCode_Success, return; );
    
    m_players[seatno] = &player;
    map<u64, CPlayerBase*>::iterator it = m_beholder.find( player.UserId() );
    SELF_ASSERT( it != m_beholder.end(), return; );
    m_beholder.erase( it );

    player.SitDown( seatno );
	++m_curPlayerCount;
    
    if( m_curPlayerCount >= CHall::Instance().MaxRoomPlayerCount() )
    {
        // 人满了从halffull队列中移除
        CRoomManager::Instance().RemoveHalfFullRoom( Id() );
    }

    commonproto::SCUserSitDownNtf ntf;
    ntf.userid = player.UserId();
    ntf.seatno = seatno;
	BroadcastMsg( commonproto::SC_USER_SITDOWN_NTF, ntf );
    
    OnPlayerSitDown( player );
    LOG_INFO( "PlayerSitDown player[%llu,%llu,%llu] sitdown room[%d] countInRoom[%d] seatno[%d] beholderCount[%d]", 
        player.GateId(), player.ClientId(), player.UserId(), Id(), m_curPlayerCount, seatno, m_beholder.size() );
}

void CRoomBase::PlayerStandUp(CPlayerBase &player)
{
    s32 ret = CanStandUp( player );
	SELF_ASSERT( ret == errorcode::E_ErrorCode_Success, return; );
	OnBeforePlayerStandUp( player );
    
    s32 seatno = player.GetSeatNo();
    m_players[seatno] = NULL;
    map<u64, CPlayerBase*>::iterator it = m_beholder.find( player.UserId() );
    SELF_ASSERT( it == m_beholder.end(), return; );
    m_beholder[ player.UserId() ] = &player;

    player.StandUp();
	--m_curPlayerCount;
        
    // 有人离开座位重新加入到halffull队列
    CRoomManager::Instance().AddHalfFullRoom( Id() );

    commonproto::SCUserStandUpNtf ntf;
    ntf.userid = player.UserId();
    ntf.seatno = seatno;
	BroadcastMsg( commonproto::SC_USER_STANDUP_NTF, ntf );
    
    OnPlayerStandUp( player );
    LOG_INFO( "PlayerStandUp player[%llu,%llu,%llu] standup room[%d] countInRoom[%d] seatno[%d] beholderCount[%d]", 
        player.GateId(), player.ClientId(), player.UserId(), Id(), m_curPlayerCount, seatno, m_beholder.size() );
}

bool CRoomBase::PlayerInRoom(CPlayerBase &player)
{
	return ( PlayerInSeat(player) || PlayerIsBeholder(player) );
}

bool CRoomBase::PlayerInSeat(CPlayerBase &player)
{
	s32 count = CHall::Instance().MaxRoomPlayerCount();
	bool ret = false;
	for( s32 i=0; i<count; ++i )
	{
		if( m_players[i] == &player &&
			m_players[i]->UserId() == player.UserId() )
		{
			ret = true;
			break;
		}
	}
	return ret;
}

bool CRoomBase::PlayerIsBeholder(CPlayerBase &player)
{
	map<u64, CPlayerBase*>::iterator it = m_beholder.find( player.UserId() );
	return ( it != m_beholder.end() );
}

void CRoomBase::PlayerReady(CPlayerBase &player)
{
    player.SetState( CPlayerBase::E_PlayerState_Ready );
    player.ClearGameEndData();

    commonproto::SCUserReadyNtf ntf;
    ntf.userid = player.UserId();
    ntf.seatno = player.GetSeatNo();
	BroadcastMsg( commonproto::SC_USER_READY_NTF, ntf );
    TryGetPriorityPlayer(player, false);
    OnPlayerReady( player );
    LOG_INFO( "room[%d] player[%llu] ready", Id(), player.UserId() );
}

void CRoomBase::PlayerCancelReady(CPlayerBase &player)
{
    player.SetState( CPlayerBase::E_PlayerState_WaitInRoom );

    commonproto::SCUserCancelReadyNtf ntf;
    ntf.userid = player.UserId();
    ntf.seatno = player.GetSeatNo();
	BroadcastMsg( commonproto::SC_USER_CANCEL_READY_NTF, ntf );
    
    OnPlayerCancelReady( player );
    LOG_INFO( "room[%d] player[%llu] cancel ready", Id(), player.UserId() );
}

void CRoomBase::PlayerTrusteeShip(CPlayerBase &player)
{
    player.SetTrusteeship( true );

    commonproto::SCTrusteeshipNtf ntf;
    ntf.userid = player.UserId();
    ntf.seatno = player.GetSeatNo();
    BroadcastMsg( commonproto::SC_TRUSTEESHIP_NTF, ntf );
}

void CRoomBase::PlayerCancelTrusteeShip(CPlayerBase &player)
{
    player.SetTrusteeship( false );

    commonproto::SCCancelTrusteeshipNtf ntf;
    ntf.userid = player.UserId();
    ntf.seatno = player.GetSeatNo();
    BroadcastMsg( commonproto::SC_CANCEL_TRUSTEESHIP_NTF, ntf );
}

void CRoomBase::PlayerRoomChat(CPlayerBase &player, s8 chattype, const std::string &chatcontent, s8 anonymous, std::vector<u64> &receiver, s8 isend, std::vector<std::string> &param)
{
    if( !CanChat(player, chattype, chatcontent, anonymous, receiver) )
    {
	    LOG_ERROR( "[%s][%s][%d] player[%llu,%llu,%llu] room[%d] can not chat. chattype[%d] anonymous[%d] receiver[%d]", 
            __FILE__, __FUNCTION__, __LINE__, 
            player.GateId(), player.ClientId(), player.UserId(), Id(), chattype, anonymous, receiver.size() );
        return;
    }

    LOG_DEBUG( "[%s][%s][%d] player[%llu,%llu,%llu] room[%d] chattype[%d] anonymous[%d] receiver[%d] isend[%d] paramsz[%d]", 
        __FILE__, __FUNCTION__, __LINE__, 
        player.GateId(), player.ClientId(), player.UserId(), Id(), chattype, 
        anonymous, receiver.size(), isend, param.size() );

    commonproto::SCRoomChatNtf ntf;
    ntf.chattype = chattype;
    ntf.chatcontent = chatcontent;
    ntf.sender = (anonymous==1) ? 0 : player.UserId();
    ntf.isend = isend;
    ntf.param = param;

    if( receiver.size() == 0 )
    {
	    BroadcastMsg( commonproto::SC_ROOM_CHAT_NTF, ntf );
    }
    else
    {
        std::vector<u64>::iterator it = receiver.begin();
        for( ; it != receiver.end(); ++it )
        {
            CPlayerBase *receiverPlayer = FindPlayer( *it );
            if( !receiverPlayer )
            {
                LOG_ERROR( "[%s][%s][%d] player[%llu,%llu,%llu] room[%d] not found receiver[%llu]. chattype[%d] anonymous[%d]", 
                        __FILE__, __FUNCTION__, __LINE__, 
                        player.GateId(), player.ClientId(), player.UserId(), Id(), *it, chattype, anonymous );
                continue;
            }

            receiverPlayer->SendMsg( commonproto::SC_ROOM_CHAT_NTF, ntf );
        }

    }
}

void CRoomBase::PlayerSetAnte(CPlayerBase &player, s32 ante)
{
    SetAnte( ante );
	LOG_INFO( "[%s][%s][%d] player[%llu] ante[%d]", __FILE__, __FUNCTION__, __LINE__, 
        player.UserId(), ante );
}

void CRoomBase::KickOutRoom(CPlayerBase &player, u64 kickuserid)
{
    s32 ret = CanKickOut( player, kickuserid );
    SELF_ASSERT( ret == errorcode::E_ErrorCode_Success, return; );
    CPlayerBase *kickuser = FindPlayer( kickuserid );
    if (!kickuser) return;
    //SELF_ASSERT( kickuser, return; );

    CHall::Instance().PlayerLeaveHall( *kickuser, commonproto::E_LeaveReason_Force );
    //CHall::Instance().PlayerLeaveFriendRoom( *kickuser );
    //CHall::Instance().PlayerLeaveRoom( *kickuser, commonproto::E_LeaveReason_Kick );
}

void CRoomBase::UseInteractItem(CPlayerBase &player, s32 to, s32 item)
{
        
}

bool CRoomBase::PlayerResetSeat(CPlayerBase &player, s32 seatno)
{
    s32 count = CHall::Instance().MaxRoomPlayerCount();
    if( seatno >= 0 && seatno < count )
    {
        m_players[ seatno ] = &player;
        player.ResetSeatNo( seatno );
        return true;
    }
    return false;
}

void CRoomBase::Dissolve(s32 reason)
{
    commonproto::SCDissolveRoomNtf ntf;
    ntf.reason = reason;
    ntf.roomid = Id();
    BroadcastMsg( commonproto::SC_ROOM_DISSOLVE_NTF, ntf );
    string bakpass = m_passwd;
	s32 count = CHall::Instance().MaxRoomPlayerCount();
	for( s32 i=0; i<count; ++i )
	{
		if( m_players[i] )
		{
			m_players[i]->DoLeaveRoom();
			m_players[i] = NULL;
		}
	}
	m_curPlayerCount = 0;
	
	map<u64, CPlayerBase*>::iterator it = m_beholder.begin();
	for( ; it != m_beholder.end(); ++it )
	{
		if( it->second )
		{
			it->second->DoLeaveRoom();
		}
	}	
	m_beholder.clear();

	SetState( CRoomBase::E_RoomState_Idle );
    Clean();
    CRoomManager::Instance().PutRoom( Id() );
    
	LOG_INFO( "[%s][%s][%d] room[%d] number[%s] dissolve", __FILE__, __FUNCTION__, __LINE__, Id(), bakpass.c_str());
}

bool CRoomBase::CheckFriendGameRoundEnd()
{
    return (CHall::Instance().IsFriendMode() &&
        GetFriendData()._curRound >= GetFriendData()._maxRound);
}

void CRoomBase::BroadcastMsg(s32 msgid, const IMessage &msg, bool tobeholder)
{
	s32 count = CHall::Instance().MaxRoomPlayerCount();
	for( s32 i=0; i<count; ++i )
	{
		if( m_players[i] )
		{
			m_players[i]->SendMsg( msgid, msg );
		}
	}

	if( tobeholder )
	{
		map<u64, CPlayerBase*>::iterator it = m_beholder.begin();
		for( ; it != m_beholder.end(); ++it )
		{
			if( it->second )
			{
				it->second->SendMsg( msgid, msg );
			}
		}
	}
}

void CRoomBase::BroadcastMsg(s32 msgid, const IMessage &msg, u64 excludePlayer, bool tobeholder)
{
    s32 count = CHall::Instance().MaxRoomPlayerCount();
    for( s32 i=0; i<count; ++i )
    {
        if( m_players[i] && m_players[i]->UserId() != excludePlayer )
        {
            m_players[i]->SendMsg( msgid, msg );
        }
    }

    if( tobeholder )
    {
        map<u64, CPlayerBase*>::iterator it = m_beholder.begin();
        for( ; it != m_beholder.end(); ++it )
        {
            if( it->second && it->second->UserId() != excludePlayer )
            {
                it->second->SendMsg( msgid, msg );
            }
        }
    }
}

void CRoomBase::BroadcastMsg2Beholder(s32 msgid, const IMessage &msg)
{
    map<u64, CPlayerBase*>::iterator it = m_beholder.begin();
    for( ; it != m_beholder.end(); ++it )
    {
        if( it->second )
        {
            it->second->SendMsg( msgid, msg );
        }
    }
}

void CRoomBase::Broadcast2Robots(s32 msgid, const IMessage &msg)
{
    s32 count = CHall::Instance().MaxRoomPlayerCount();
    for( s32 i=0; i<count; ++i )
    {
        if( m_players[i] && m_players[i]->IsRobot() )
        {
            m_players[i]->SendMsg( msgid, msg );
        }
    }
}

void CRoomBase::CheckActionTimeOut(u64 now)
{
    s32 count = CHall::Instance().MaxRoomPlayerCount();
    for( s32 i=0; i<count; ++i )
    {
        if( m_players[i] )
        {
            if( m_players[i]->IsActionTimeOut(now) )
            {
                m_players[i]->ActionTimeOut(); 
            }
        }
        if( m_players[i] )
        {
            // ActionTimeOut 可能会移除players
            m_players[i]->CheckMoreActionTimeOut( now );
        }
    }
}

void CRoomBase::CheckMoreTimeOut(u64 now)
{
    _CheckFriendRoomExpire( now );
}

void CRoomBase::CleanBreakUsers()
{
    s32 count = CHall::Instance().MaxRoomPlayerCount();
    for( s32 i=0; i<count; ++i )
    {
        if( m_players[i] && m_players[i]->IsOffline() )
        {
            LOG_INFO( "[%s][%s][%d] room[%d] clean breakUser[%llu] ",
                    __FILE__, __FUNCTION__, __LINE__, Id(), m_players[i]->UserId() );
            CHall::Instance().PlayerLeaveHall( *m_players[i], commonproto::E_LeaveReason_Kick );
        }
    }
}

void CRoomBase::KickOutPlayer(CPlayerBase &player, s32 reason)
{
	LOG_INFO( "[%s][%s][%d] room[%d] kickout user[%llu] reason[%d]",
		__FILE__, __FUNCTION__, __LINE__, Id(), player.UserId(), reason );

	commonproto::SCKickOutNtf ntf;
	ntf.reason = reason;
	player.SendMsg( commonproto::SC_KICK_OUT_NTF, ntf );

	PlayerLeave( player, reason );
}

void CRoomBase::NotifyRoomBasicInfos(CPlayerBase &player)
{
    commonproto::SCRoomExistUserInfoNtf msg;
    s32 count = CHall::Instance().MaxRoomPlayerCount();
    for( s32 i=0; i<count; ++i )
    {
        if( m_players[i] /*&& m_players[i]->UserId() != player.UserId()*/ )
        {
            commonproto::BasicRoomUserInfo info;
            info.userid = m_players[i]->UserId();
            info.seatno = i;
            info.isready = (m_players[i]->State() == CPlayerBase::E_PlayerState_Ready) ? 1 : 0;
            info.basicinfo = m_players[i]->GetBasicInfo();
            info.gamedata = m_players[i]->GetGameData();
            info.onstate = m_players[i]->AddiStatus();
            msg.userinfos.push_back( info );
            if ((int)msg.userinfos.size() >= BASICINFO_BATCH_LEN) {
                player.SendMsg( commonproto::SC_ROOM_EXIST_USER_INFO_NTF, msg );
                msg.userinfos.clear();
            }
        }
    }
    map<u64, CPlayerBase*>::iterator it = m_beholder.begin();
    for( ; it != m_beholder.end(); ++it )
    {
        if( it->second /*&& it->second->UserId() != player.UserId()*/ )
        {
            commonproto::BasicRoomUserInfo info;
            info.userid = it->second->UserId();
            info.seatno = INVALID_SEAT;
            info.isready = 0;
            info.basicinfo = it->second->GetBasicInfo();
            info.gamedata = it->second->GetGameData();
            msg.otheruserinfos.push_back( info );
            if (msg.userinfos.size()+msg.otheruserinfos.size() >= (size_t)BASICINFO_BATCH_LEN) {
                player.SendMsg( commonproto::SC_ROOM_EXIST_USER_INFO_NTF, msg );
                msg.userinfos.clear();
                msg.otheruserinfos.clear();
            }
        }
    }
    if (msg.userinfos.size()+msg.otheruserinfos.size() > 0) {
        player.SendMsg( commonproto::SC_ROOM_EXIST_USER_INFO_NTF, msg );
    }
}

void CRoomBase::DumpBasicInfo(commonproto::RoomBasicInfo &info)
{
    info.roomid = Id();
    info.data = m_data;
    info.curcount = CurPlayerCount();
    info.maxcount = CHall::Instance().MaxRoomPlayerCount();
}

void CRoomBase::DumpAllSeatPlayers(std::vector<CPlayerBase*> &players, std::vector<char> &isready)
{
    players.clear();
    s32 count = CHall::Instance().MaxRoomPlayerCount();
    for( s32 i=0; i<count; ++i )
    {
        if( m_players[i] )
        {
            players.push_back( m_players[i] );
            isready.push_back( m_players[i]->HasReady() ? 1 : 0 );
        }
    }
}

void CRoomBase::DumpAllBeholderPlayers(std::vector<CPlayerBase*> &players)
{
    players.clear();
    map<u64, CPlayerBase*>::iterator it = m_beholder.begin();
    for( ; it != m_beholder.end(); ++it )
    {
        if( it->second )
        {
            players.push_back( it->second );
        }
    }
}

void CRoomBase::_GameEndCheckActivity()
{
    s32 count = CHall::Instance().MaxRoomPlayerCount();
	for( s32 i=0; i<count; ++i )
	{
		if( m_players[i] )
		{
            m_players[i]->GameEndCheckActivity();
        }
    }
}

void CRoomBase::_ClearAllAgreeDismissAction()
{
    GetFriendData()._dismissState = -1;
    std::set<s32>::iterator it = GetFriendData()._waitDismissUser.begin();
    for( ; it != GetFriendData()._waitDismissUser.end(); ++it )
    {
        s32 seatno = *it;
        CPlayerBase *player = GetPlayerInSeat( seatno );
        if( player )
        {
            player->DelMoreAction( commonproto::Action_AgreeDismissFriendRoom );
        }
    }

    LOG_DEBUG( "[%s] clear [%d] agree action", 
        __FUNCTION__, GetFriendData()._waitDismissUser.size() );

    GetFriendData()._waitDismissUser.clear();
}

void CRoomBase::_DumpAllBreakPlayers(std::vector<CPlayerBase*> &players, bool all)
{
    players.clear();
    s32 count = CHall::Instance().MaxRoomPlayerCount();
    if (all) {
        for( s32 i=0; i<count; ++i )
        {
            if( m_players[i])
            {
                players.push_back( m_players[i] );
            }
        }
    } else {
        for( s32 i=0; i<count; ++i )
        {
            if( m_players[i] && m_players[i]->IsOffline() )
            {
                players.push_back( m_players[i] );
            }
        }
        map<u64, CPlayerBase*>::iterator it = m_beholder.begin();
        for( ; it != m_beholder.end(); ++it )
        {
            if( it->second && it->second->IsOffline() )
            {
                players.push_back( it->second );
            }
        }
    }
}

void CRoomBase::_CleanBreakPlayers(std::vector<CPlayerBase*> &players)
{
    int n = 0;
    vector<CPlayerBase*>::iterator it = players.begin();
    for( ; it != players.end(); ++it )
    {
        if( *it )
        {
            ++n;
            CHall::Instance().PlayerLeaveHall( *(*it), commonproto::E_LeaveReason_Kick );
            LOG_DEBUG( "[%s][%s][%d] room[%d] clean user[%llu] addistatus[%u]",
                    __FILE__, __FUNCTION__, __LINE__, Id(), (*it)->UserId(), (*it)->AddiStatus() );
        }
    }
    LOG_INFO( "[%s][%s][%d] room[%d] clean [%d/%d] break player",
        __FILE__, __FUNCTION__, __LINE__, Id(), n, (s32)players.size() );
}

void CRoomBase::_CheckFriendRoomExpire(u64 now)
{
    if( !CHall::Instance().IsFriendMode() )
    {
        return;
    }
    if( State() == CRoomBase::E_RoomState_Idle )
    {
        return;
    }

    // 房间总时间到了或是未开始的房间达到过期期限了
    s32 interval = (s32)(now - GetFriendData()._createTime);
    if( interval >= CHallConfig::Instance().GetCfg().friendRoomExpireSec ||
        (GetFriendData()._curRound == 0 &&
         interval >= CHallConfig::Instance().GetCfg().friendRoomIdleExpireSec) )
    {
        OnFriendGameDismiss( commonproto::E_FRoomEnd_Dismiss );
        vector<CPlayerBase*> _breakers;
        _DumpAllBreakPlayers( _breakers, true);
        Dissolve( commonproto::E_DissolveReason_Destory );
        CHall::Instance().NotifyRoomCenterGameStop( *this, roomcenter::GameStopReason_Dismiss );
        _CleanBreakPlayers( _breakers );
        LOG_INFO( "[%s][%s][%d] room[%d] breakers[%d]",
            __FILE__, __FUNCTION__, __LINE__, Id(), _breakers.size() );
    }
}

void CRoomBase::_logBreakPlayersGameEnd(std::vector<CPlayerBase*> &players)
{
    dbcommon::GameDBProxyBreakUserGameEnd m;
    m.score = 0;
    m.gameid = CHall::Instance().GameId();
    m.roommode = CHallConfig::Instance().GetCfg().roomMode; 
    vector<CPlayerBase*>::iterator it = players.begin();
    for( ; it != players.end(); ++it )
    {
        m.userid = (*it)->UserId();
        bool ret = CHall::Instance().SendMsg2DBProxy( dbcommon::GAME_DBPROXY_BREAK_USER_GAME_END, m, m.userid );
        if( !ret )
        {
            LOG_ERROR( "[%s][%s][%d] user[%llu]", 
                __FILE__, __FUNCTION__, __LINE__, m.userid );
        }
    }
}

void CRoomBase::NotifyUserLocationInfo(CPlayerBase *player)
{
    commonproto::SCUserLocationInfoNtf ntf;
    s32 count = CHall::Instance().MaxRoomPlayerCount();
    for( s32 i=0; i<count; ++i )
    {
        if( m_players[i] )
        {
            commonproto::UserLocationInfo info;
            info.seat = i;
            info.info = m_players[i]->GetLocation();
            ntf.infos.push_back( info );
        }
    }
    if( !player )
    {
        BroadcastMsg( commonproto::SC_USER_LOCATION_INFO_NTF, ntf );
    }
    else
    {
        player->SendMsg( commonproto::SC_USER_LOCATION_INFO_NTF, ntf );
    }
}

bool CRoomBase::CreaterInRoom()
{
    s32 count = CHall::Instance().MaxRoomPlayerCount();
    for( s32 i=0; i<count; ++i )
    {
        if( m_players[i] && m_players[i]->UserId() == m_friendData._creater )
        {
            return true;      
        }
    }
    return false;
}


